//////////////////////////////////////////////////////////////////////
////                                                              ////
////  OPBFlash.v                                                  ////
////                                                              ////
////                                                              ////
////  This file is part of the "PICO" project                     ////
////  http://www.picocomputing.com                                ////
////                                                              ////
////                                                              ////
//////////////////////////////////////////////////////////////////////
////                                                              ////
//// Copyright (C) 2004, Pico Computing, Inc.                     ////
//// http://www.picocomputing.com                                 ////
////                                                              ////
//// This source file may be used and distributed without         ////
//// restriction provided that this copyright statement is not    ////
//// removed from the file and that any derivative work contains  ////
//// the original copyright notice and the associated disclaimer. ////
////                                                              ////
//// This source file is free software; you can redistribute it   ////
//// and/or modify it under the terms of the GNU Lesser General   ////
//// Public License as published by the Free Software Foundation; ////
//// either version 2.1 of the License, or (at your option) any   ////
//// later version.                                               ////
////                                                              ////
//// This source is distributed in the hope that it will be       ////
//// useful, but WITHOUT ANY WARRANTY; without even the implied   ////
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      ////
//// PURPOSE.  See the GNU Lesser General Public License for more ////
//// details.                                                     ////
////                                                              ////
//// You should have received a copy of the GNU Lesser General    ////
//// Public License along with this source; if not, download it   ////
//// from http://www.opencores.org/lgpl.shtml                     ////
////                                                              ////
////////////////////////////////////////////////////////////////////DH

`include "PicoDefines.v"

module OPBMemBridge(
   Clk200, MemAddr, MemDIn, MemDOut, MemWait, IOReadMaster, IOWriteMaster, MemReadMaster, MemWriteMaster, AttrReadMaster, AttrWriteMaster,
   OPB_Clk, OPB_Clk90, OPB_Rst, OPB_ABus, OPB_BE, OPB_DBus,                  //OPB -> Slave Signals
   OPB_RNW, OPB_select, OPB_seqAddr,
   Sl_DBus, Sl_errAck, Sl_retry, Sl_toutSup, Sl_xferAck           //Slave -> OPB Signals
   ,test_pins
);

parameter C_OPB_AWIDTH = 32;
parameter C_OPB_DWIDTH = 32;
parameter C_BASEADDR   = `OPB_BUSBRIDGE_BASEADDR;
parameter C_HIGHADDR   = `OPB_BUSBRIDGE_HIGHADDR;

input         Clk200;
output [31:0] MemAddr;
output [15:0] MemDIn;
input  [15:0] MemDOut;
input         MemWait;
output        IOReadMaster, IOWriteMaster;
output        MemReadMaster, MemWriteMaster;
output        AttrReadMaster, AttrWriteMaster;

input OPB_Clk;
input OPB_Clk90;
input OPB_Rst;
input [C_OPB_AWIDTH-1:0] OPB_ABus;
input [(C_OPB_DWIDTH/8)-1:0] OPB_BE;
input [C_OPB_DWIDTH-1:0] OPB_DBus;
input OPB_RNW;
input OPB_select;
input OPB_seqAddr;
output [C_OPB_DWIDTH-1:0] Sl_DBus;
output Sl_errAck;
output Sl_retry;
output Sl_toutSup;
output Sl_xferAck;

output [127:0] test_pins;

reg [4:0] AddrWindowReg;
reg [1:0] AccessType = 0;  // common mem, attr mem, or io

// latches for OPB signals
reg OpbEnLatch = 0;
reg OpbEnSemiDelayed = 0;
reg OpbEnDelayed = 0; // lags OpbEnLatch by one OPB_Clk cycle. excessive, but as long as we're waiting ages for the flash, who cares?
reg OPB_RNWLatch;
reg [15:0] MemDOutLatch;
reg [1:0] OPB_RNWDelay = 0;
reg Inhibit = 0;
reg AckReg;

always @(posedge Clk200)
   OPB_RNWDelay[1:0] <= {OPB_RNWDelay[0], OPB_RNW};

// generate read and write signals
wire opb_en            = OPB_select & (OPB_ABus >= C_BASEADDR && OPB_ABus <= C_HIGHADDR);
wire ThePulse          = (OpbEnSemiDelayed == 1'b1) & (OpbEnDelayed == 1'b0);
wire read			   = OpbEnLatch &&  OPB_RNW && ~Inhibit;
wire write			   = OpbEnLatch && ~OPB_RNW && ~Inhibit;
assign MemReadMaster   = read  && (AccessType == 2'b00);
assign MemWriteMaster  = write && (AccessType == 2'b00);
assign AttrReadMaster  = read  && (AccessType == 2'b01);
assign AttrWriteMaster = write && (AccessType == 2'b01);
assign IOReadMaster    = read  && (AccessType == 2'b10);
assign IOWriteMaster   = write && (AccessType == 2'b10);
wire window_reg_write  = OPB_select & (OPB_ABus[31:0] == `OPB_BUSBRIDGE_WINDOW_REG_ADDR);
wire access_type_write = OPB_select & (OPB_ABus[31:0] == `OPB_BUSBRIDGE_ACCESS_TYPE_ADDR);

assign MemAddr[31:0] = {AddrWindowReg[4:0], OPB_ABus[26:0]};

assign MemDIn[15:0] = OPB_DBus[15:0];
assign Sl_DBus = (opb_en & OPB_RNW) ? /*{MemDOut, MemDOutLatch}*/ {MemDOut[7:0], MemDOut[15:8], MemDOut[7:0], MemDOut[15:8]}: 32'h0;

// this logic is insane. clean it up!
always @(posedge OPB_Clk)
   begin
      OpbEnLatch          <= opb_en && ~Sl_xferAck;
      OpbEnSemiDelayed    <= OpbEnLatch | (OpbEnSemiDelayed & MemWait);
      OpbEnDelayed        <= OpbEnSemiDelayed & ~MemWait;
      AckReg              <= OpbEnSemiDelayed & ~OpbEnDelayed & ~MemWait;
   end

// if we're writing, lower the write signal half a cycle before the data and addr will go invalid
always @(negedge OPB_Clk)
   Inhibit <= Sl_xferAck && ~OPB_RNW;

always @(posedge window_reg_write or posedge OPB_Rst) 
   begin
    if (OPB_Rst) AddrWindowReg <= 5'h0;
    else         AddrWindowReg <= OPB_DBus[31:27]; // not the usual pico method, but this is convenient for software (no shifting).
   end

always @(posedge access_type_write or posedge OPB_Rst) 
   begin
    if (OPB_Rst) AccessType <= 2'h0;
    else         AccessType <= OPB_DBus[1:0];
   end

//assign Sl_xferAck = AckReg;

always @(posedge Sl_xferAck)
   MemDOutLatch <= MemDOut;

/* Flash transactions will take up to 120ns to complete */
///\TODO: the clock's changed so this delay is probably wrong
OPBWait #(.OPB_WAIT_CYCLES(12)) opb_wait(
   .opb_en(opb_en),
   .OPB_Clk(OPB_Clk),
   .OPB_Rst(OPB_Rst),
   .Sl_xferAck(Sl_xferAck)
);

assign Sl_errAck  = 1'b0;
assign Sl_retry   = 1'b0;
assign Sl_toutSup = 1'b0;

`ifdef ENABLE_DEBUG_TAPS

wire [100:0] keeper;
//synthesis attribute KEEP of keeper is TRUE;
DebugTap #(.Width(32)) OPB_ABus_tap (OPB_ABus[31:0], keeper[0]);
DebugTap #(.Width(16)) OPB_DBus_tap (OPB_DBus[15:0], keeper[1]);
DebugTap #(.Width(16)) Sl_DBus_tap (Sl_DBus[15:0], keeper[2]);
DebugTap #(.Width(4))  OPB_BE_tap (OPB_BE[3:0], keeper[3]);
DebugTap #(.Width(1))  OPB_select_tap (OPB_select, keeper[4]);
DebugTap #(.Width(1))  OPB_RNW_tap (OPB_RNW, keeper[5]);
DebugTap #(.Width(1))  OPB_Clk_tap (OPB_Clk, keeper[6]);
DebugTap #(.Width(1))  Sl_xferAck_tap (Sl_xferAck, keeper[7]);
DebugTap #(.Width(1))  opb_en_tap (opb_en, keeper[8]);
DebugTap #(.Width(2))  OPB_RNWDelay_tap (OPB_RNWDelay, keeper[9]);
DebugTap #(.Width(1))  MemWait_tap (MemWait, keeper[10]);
DebugTap #(.Width(1))  OpbEnLatch_tap (OpbEnLatch, keeper[11]);
`endif // ENABLE_DEBUG_TAPS

endmodule
